/*  SSEventLinkObject.m
 *  MESLib
 * 
 * Copyright 2003-2009 Starline Software Ltd
 * 
 * This file is part of MESLib.
 * 
 * MESLib is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * MESLib is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with MESLib. If not, see <http://www.gnu.org/licenses/>.
 */
//  Created by Tobias Haughton on Sat Jan 25 2003.
//

#import "SSEventLinkObject.h"
#import "SSEventObject.h"
#import "SSCatalystDocument.h"

@implementation SSEventLinkObject

- (id)initWithLinkedFrom:(SSEventObject *)from linkedTo:(SSEventObject *)to type:(NSNumber *)type
{
   if (self = [super init]) {
      linkedFrom = from;
      linkedTo = to;
      [linkedTo addLinkFrom:linkedFrom];

      thePath = [[NSBezierPath alloc] init];
      arrowPath = [[NSBezierPath alloc] init];
      tentativeString = [[NSAttributedString alloc] initWithString:@"?"];
      needsDiamondArray = [[NSMutableArray alloc] init];
      [self setLinkType:type];
      
      [self setPoints];
      [self setArrows];

      [thePath setLineWidth:SSConnectorLineWidth];

      [self setPaths];
   }
   return self;
}

- (void)setPoints
{
   if([linkedFrom displayMode] == SSOverlapDisplayMode) {
      [self setPointsForOverlapDisplay];
   } else {
      [self setPointsForMatrixDisplay];
   }
}

- (void)setPointsForMatrixDisplay
{
   //taken from chartConstructor
   //sets the points between which the path will be drawn
   if(NSMinY([linkedTo frame]) == NSMinY([linkedFrom frame])) { //it's directally to the left or right
      if(NSMinX([linkedTo frame]) < NSMinX([linkedFrom frame])) { //it's too the left
         startPoint = [linkedFrom leftPoint];
         endPoint = [self moveRight:[linkedTo rightPoint]];
         tentativeStringPoint = NSMakePoint((endPoint.x + 10), (endPoint.y - 20)); //put ? above link
      } else { //it's too the right
         startPoint = [linkedFrom rightPoint];
         endPoint = [self moveLeft:[linkedTo leftPoint]];
         tentativeStringPoint = NSMakePoint((endPoint.x - 10), (endPoint.y - 20)); //put ? above link
      }
   } else {
      if(NSMinX([linkedTo frame]) == NSMinX([linkedFrom frame])) { //it's directly above or below
         if(NSMinY([linkedTo frame]) < NSMinY([linkedFrom frame])) { //it's above
            startPoint = [linkedFrom topPoint];
            endPoint = [self moveDown:[linkedTo bottomPoint]];
            tentativeStringPoint = NSMakePoint((endPoint.x + 10), endPoint.y); //put ? to right of link
         } else { //it's below
            startPoint = [linkedFrom bottomPoint];
            endPoint = [self moveUp:[linkedTo topPoint]];
            tentativeStringPoint = NSMakePoint((endPoint.x + 10), (endPoint.y - 15)); //put ? to right of link
         }
      } else {
         if(NSMinY([linkedTo frame]) < NSMinY([linkedFrom frame])) { //it's above and off to one side
            if([linkedTo centerPoint].x < [linkedFrom centerPoint].x) { //it's above and to the left
               if(NSMaxY([linkedTo frame]) < NSMinY([linkedFrom frame])) { //it's way above so connect to the bottom right
                  startPoint = [linkedFrom topPoint];
                  endPoint = [self moveDown:[linkedTo bottomRightPoint]];
                  tentativeStringPoint = NSMakePoint((endPoint.x + 10), endPoint.y);  //put ? to right of link
               } else { //it's left and roughly equal on the y axis so connect from the side
                  startPoint = [linkedFrom leftPoint];
                  endPoint = [self moveRight:[linkedTo rightBottomPoint]];
                  tentativeStringPoint = NSMakePoint(endPoint.x, (endPoint.y - 20)); //put ? above link
               }
            } else { //its above and to the right
               if(NSMaxY([linkedTo frame]) < NSMinY([linkedFrom frame])) { //it's way above so connect to the bottom left
                  startPoint = [linkedFrom topPoint];
                  endPoint = [self moveDown:[linkedTo bottomLeftPoint]];
                  tentativeStringPoint = NSMakePoint((endPoint.x + 10), endPoint.y); //put ? to right of link
               } else {//it's roughly equal on the y axis connect to the side
                  startPoint = [linkedFrom leftPoint];
                  endPoint = [self moveLeft:[linkedTo leftBottomPoint]];
                  tentativeStringPoint = NSMakePoint(endPoint.x, (endPoint.y - 20));  //put ? above of link
               }
            }
         } else { //its below and to one side
            if([linkedTo centerPoint].x < [linkedFrom centerPoint].x) { //it's below and to the left
               if(NSMinY([linkedTo frame]) > NSMaxY([linkedFrom frame])) { //it's way below connect to the top right side
                  startPoint = [linkedFrom bottomPoint];
                  endPoint = [self moveUp:[linkedTo topRightPoint]];
                  tentativeStringPoint = NSMakePoint((endPoint.x - 10), (endPoint.y - 15));  //put ? to left of link
               } else { //y axis is roughly equal connect to the side
                  startPoint = [linkedFrom leftPoint];
                  endPoint = [self moveRight:[linkedTo rightTopPoint]];
                  tentativeStringPoint = NSMakePoint(endPoint.x, (endPoint.y - 20));  //put ?  above link
               }
            } else { //it's below and to the right
               if(NSMinY([linkedTo frame]) > NSMaxY([linkedFrom frame])) { //it's way below connect to the top left side
                  startPoint = [linkedFrom bottomPoint];
                  endPoint = [self moveUp:[linkedTo topLeftPoint]];
                  tentativeStringPoint = NSMakePoint((endPoint.x - 10), (endPoint.y - 15));  //put ? to left of link
               } else { //y axis is roughly equal connect to the side
                  startPoint = [linkedFrom rightPoint];
                  endPoint = [self moveLeft:[linkedTo leftTopPoint]];
                  tentativeStringPoint = NSMakePoint(endPoint.x, (endPoint.y - 20));  //put ? above link
               }
            }
         }
      }
   }
}

- (void)setPointsForOverlapDisplay
{
   //sets the points between which the path will be drawn
   if(NSMinY([linkedTo frame]) == NSMinY([linkedFrom frame])) { //it's directally to the left or right
      if(NSMinX([linkedTo frame]) < NSMinX([linkedFrom frame])) { //it's too the left
         startPoint = [linkedFrom leftPoint];
         endPoint = [self moveRight:[linkedTo rightPoint]];
         tentativeStringPoint = NSMakePoint((endPoint.x + 10), (endPoint.y - 20)); //put ? above link
      } else { //it's too the right
         startPoint = [linkedFrom rightPoint];
         endPoint = [self moveLeft:[linkedTo leftPoint]];
         tentativeStringPoint = NSMakePoint((endPoint.x - 10), (endPoint.y - 20)); //put ? above link
      }
   } else {
      if(NSMinX([linkedTo frame]) == NSMinX([linkedFrom frame])) { //it's directly above or below
         if(NSMinY([linkedTo frame]) < NSMinY([linkedFrom frame])) { //it's above
            startPoint = [linkedFrom topLeftPoint];
            endPoint = [self moveDown:[linkedTo bottomPoint]];
            tentativeStringPoint = NSMakePoint((endPoint.x + 10), endPoint.y); //put ? to right of link
         } else { //it's below
            startPoint = [linkedFrom bottomLeftPoint];
            endPoint = [self moveUp:[linkedTo topPoint]];
            tentativeStringPoint = NSMakePoint((endPoint.x + 10), (endPoint.y - 15)); //put ? to right of link
         }
      } else {
         if(NSMinY([linkedTo frame]) < NSMinY([linkedFrom frame])) { //it's above and off to one side
            if([linkedTo centerPoint].x < [linkedFrom centerPoint].x) { //it's above and to the left
               if(NSMaxY([linkedTo frame]) < NSMinY([linkedFrom frame])) { //it's way above so connect to the bottom right
                  startPoint = [linkedFrom topPoint];
                  endPoint = [self moveDown:[linkedTo bottomRightPoint]];
                  tentativeStringPoint = NSMakePoint((endPoint.x + 10), endPoint.y);  //put ? to right of link
               } else { //it's left and roughly equal on the y axis so connect from the side
                  startPoint = [linkedFrom leftPoint];
                  endPoint = [self moveRight:[linkedTo rightBottomPoint]];
                  tentativeStringPoint = NSMakePoint(endPoint.x, (endPoint.y - 20)); //put ? above link
               }
            } else { //its above and to the right
               if([linkedFrom centerPoint].x < NSMinX([linkedTo frame])) {
                  startPoint = [linkedFrom centerPoint];
                  endPoint = [self moveDown:[linkedTo bottomLeftPoint]];
                  tentativeStringPoint = NSMakePoint((endPoint.x + 10), endPoint.y); //put ? to right of link
               } else {
                  startPoint = [linkedFrom topLeftPoint];
                  endPoint = [self moveDown:[linkedTo bottomLeftPoint]];
                  tentativeStringPoint = NSMakePoint((endPoint.x + 10), endPoint.y); //put ? to right of link
               }
            }
         } else { //its below and to one side
            if([linkedTo centerPoint].x < [linkedFrom centerPoint].x) { //it's below and to the left
               if(NSMinY([linkedTo frame]) > NSMaxY([linkedFrom frame])) { //it's way below connect to the top right side
                  startPoint = [linkedFrom bottomPoint];
                  endPoint = [self moveUp:[linkedTo topRightPoint]];
                  tentativeStringPoint = NSMakePoint((endPoint.x - 10), (endPoint.y - 15));  //put ? to left of link
               } else { //y axis is roughly equal connect to the side
                  startPoint = [linkedFrom leftPoint];
                  endPoint = [self moveRight:[linkedTo rightTopPoint]];
                  tentativeStringPoint = NSMakePoint(endPoint.x, (endPoint.y - 20));  //put ?  above link
               }
            } else { //it's below and to the right
               if([linkedFrom centerPoint].x < NSMinX([linkedTo frame])) {
                  startPoint = [linkedFrom centerPoint];
                  endPoint = [self moveDown:[linkedTo topLeftPoint]];
                  tentativeStringPoint = NSMakePoint((endPoint.x - 10), (endPoint.y - 15));  //put ? to left of link
               } else {
                  startPoint = [linkedFrom bottomLeftPoint];
                  endPoint = [self moveDown:[linkedTo topLeftPoint]];
                  tentativeStringPoint = NSMakePoint((endPoint.x - 10), (endPoint.y - 15));  //put ? to left of link
               }
            }
         }
      }
   }
}

- (void)setArrows
{
   //taken from chartConstructor
   float slope = ((endPoint.y - startPoint.y)/(endPoint.x - startPoint.x));
   float run, rise;
   float beta = pi/4;
   float alpha = atan(slope);

   if(startPoint.x == endPoint.x) {//line is vertical
      arrowPoint1 = NSMakePoint(endPoint.x + SSArrowLength * cos(alpha + beta / 2)
                                , endPoint.y - SSArrowLength * sin(alpha + beta / 2));

      arrowPoint2 = NSMakePoint(endPoint.x + SSArrowLength * cos(alpha - beta / 2)
                                , endPoint.y - SSArrowLength * sin(alpha - beta / 2));
   } else {
      if(startPoint.y == endPoint.y) { //line is horizontal
         if(startPoint.x < endPoint.x) { //line is going right
            arrowPoint1 = NSMakePoint(endPoint.x - SSArrowLength * cos(alpha + beta / 2)
                                      , endPoint.y + SSArrowLength * sin(alpha + beta / 2));

            arrowPoint2 = NSMakePoint(endPoint.x - SSArrowLength * cos(alpha - beta / 2)
                                      , endPoint.y + SSArrowLength * sin(alpha - beta / 2));

         } else { //line is going right to left
            arrowPoint1 = NSMakePoint(endPoint.x + SSArrowLength * cos(alpha + beta / 2)
                                      , endPoint.y - SSArrowLength * sin(alpha + beta / 2));

            arrowPoint2 = NSMakePoint(endPoint.x + SSArrowLength * cos(alpha - beta / 2)
                                      , endPoint.y - SSArrowLength * sin(alpha - beta / 2));
         }
      } else {
         if(startPoint.x < endPoint.x) { //line is going left to right
            run = endPoint.x - startPoint.x;
            rise = startPoint.y - endPoint.y;
            slope = rise/run;
            alpha = atan(slope);

            if(startPoint.y < endPoint.y) { //line is going down right
               arrowPoint1 = NSMakePoint(endPoint.x - SSArrowLength * cos(alpha - beta / 2)
                                         , endPoint.y + SSArrowLength * sin(alpha - beta / 2));

               arrowPoint2 = NSMakePoint(endPoint.x - SSArrowLength * cos(alpha + beta / 2)
                                         , endPoint.y + SSArrowLength * sin(alpha + beta / 2));

            } else { //line is going up right
               arrowPoint1 = NSMakePoint(endPoint.x - SSArrowLength * cos(alpha + beta / 2)
                                         , endPoint.y + SSArrowLength * sin(alpha + beta / 2));

               arrowPoint2 = NSMakePoint(endPoint.x - SSArrowLength * cos(alpha - beta / 2)
                                         , endPoint.y + SSArrowLength * sin(alpha - beta / 2));
            }
         } else { //line is going right to left
            run = startPoint.x - endPoint.x;
            rise = endPoint.y - startPoint.y;
            slope = rise/run;
            alpha = atan(slope);

            if(startPoint.y < endPoint.y) { //line is going down left
               arrowPoint1 = NSMakePoint(endPoint.x + SSArrowLength * cos(alpha - beta / 2)
                                         , endPoint.y - SSArrowLength * sin(alpha - beta / 2));

               arrowPoint2 = NSMakePoint(endPoint.x + SSArrowLength * cos(alpha + beta / 2)
                                         , endPoint.y - SSArrowLength * sin(alpha + beta / 2));
            } else { //line is going up left
               arrowPoint1 = NSMakePoint(endPoint.x + SSArrowLength * cos(alpha + beta / 2)
                                         , endPoint.y - SSArrowLength * sin(alpha + beta / 2));

               arrowPoint2 = NSMakePoint(endPoint.x + SSArrowLength * cos(alpha - beta / 2)
                                         , endPoint.y - SSArrowLength * sin(alpha - beta / 2));
            }
         }
      }
   }
}

//***********************************
- (NSPoint)moveUp:(NSPoint)p
{
   p.y -= SSArrowDistanceFromEventView;
   return p;
}

- (NSPoint)moveDown:(NSPoint)p
{
   p.y += SSArrowDistanceFromEventView;
   return p;
}

- (NSPoint)moveLeft:(NSPoint)p
{
   p.x -= SSArrowDistanceFromEventView;
   return p;
}

- (NSPoint)moveRight:(NSPoint)p
{
   p.x += SSArrowDistanceFromEventView;
   return p;
}

//***********************************
- (NSNumber *)linkType
{
   return linkType;
}

- (NSString *)linkTypeString
{
   switch([[self linkType] intValue]) {
      case SSConfirmedLinkType:return @"confirmed";
           break;
      default:return @"tentative";
         break;
   }
}

- (void)setLinkType:(NSNumber *)type
{
   [linkType release];
   [type retain];
   linkType = type;
}

- (SSEventObject *)linkedTo
{
   return linkedTo;
}

- (SSEventObject *)linkedFrom
{
   return linkedFrom;
}

- (void)setLinkedTo:(SSEventObject *)object
{
   [linkedTo release];
   linkedTo = [object retain];
}

- (void)setLinkedFrom:(SSEventObject *)object
{
   [linkedFrom release];
   linkedFrom = [object retain];
}

- (void)removeLinkTo
{
   [linkedTo removeLinkFrom:linkedFrom];
}

- (void)changeLinkType
{
   //set the link type to the oposite of the current link type
   if([linkType intValue] == SSConfirmedLinkType) {
      [self setLinkType:[NSNumber numberWithInt:SSTentativeLinkType]];
   } else {
      [self setLinkType:[NSNumber numberWithInt:SSConfirmedLinkType]];

      //get rid of the line dash
      float pat[2] = {0.0, 0.0};
      [thePath setLineDash:pat count:2 phase:0.0];
   }

   [self update];
   
   //get the document to re display the view
   [[[NSDocumentController sharedDocumentController] currentDocument] reload];
}

- (void)changeLinkTypeTo:(NSNumber *)t
{
   [self setLinkType:t];

   //get rid of the line dash
   float pat[2] = {0.0, 0.0};
   [thePath setLineDash:pat count:2 phase:0.0];

   [self update];

   //get the document to re display the view
   [[[NSDocumentController sharedDocumentController] currentDocument] redisplay];
}

- (void)setPaths
{
   double run = endPoint.x - startPoint.x;
   double rise = startPoint.y - endPoint.y;
   double slope = rise/run;
   double alpha = atan(slope);
   
   [thePath moveToPoint:startPoint];

   //set the ending point for the line
   if(startPoint.x == endPoint.x) {//line is vertical
      if(startPoint.y < endPoint.y) {
         //it is heading down
         [thePath lineToPoint:NSMakePoint(endPoint.x, (endPoint.y - SSArrowLength))];
      } else {
         //it is heading up
         [thePath lineToPoint:NSMakePoint(endPoint.x, (endPoint.y + SSArrowLength))];
      }
   } else if(startPoint.y == endPoint.y) { //line is horizontal
      if(startPoint.x < endPoint.x) { //line is going right
         [thePath lineToPoint:NSMakePoint((endPoint.x - SSArrowLength), endPoint.y)];

      } else { //line is going right to left
         [thePath lineToPoint:NSMakePoint((endPoint.x + SSArrowLength), endPoint.y)];
      }
   } else if(startPoint.x < endPoint.x) { //line is going on an angle left to right
      [thePath lineToPoint:NSMakePoint(endPoint.x - SSArrowLength * cos(alpha), endPoint.y + SSArrowLength * sin(alpha))];
   } else { //line is going on an angle right to left
      [thePath lineToPoint:NSMakePoint(endPoint.x + SSArrowLength * cos(alpha), endPoint.y - SSArrowLength * sin(alpha))];
      
   }
   
   if([linkType intValue] == SSTentativeLinkType) {
      float pat[2] = {4.0, 3.0};
      [thePath setLineDash:pat count:2 phase: 0.0];
   }
   
   [arrowPath moveToPoint:endPoint];
   [arrowPath lineToPoint:arrowPoint1];
   [arrowPath lineToPoint:arrowPoint2];
   [arrowPath closePath];
}

- (void)stroke
{
   if(![self isSelected]) {
      NSComparisonResult result = [[linkedFrom beginTime] compare:[linkedTo beginTime]];

      if(result == NSOrderedDescending) {
         [[NSColor redColor] set]; //linkedTo starts before linkedFrom starts so make the link red
         [thePath setLineWidth:3];
         [thePath stroke];
      } else { //the times are correct what about EB position?
         if(NSMinX([linkedFrom frame]) > NSMinX([linkedTo frame])) {
            //linkedTo is to the left of linkedFrom set color to red
            [[NSColor redColor] set];
         } else {
            [[NSColor blackColor] set];
         }
         [thePath setLineWidth:1];
         [thePath stroke];
      }
   } else {
      //we are selected so use the selected color
      [SSSelectedColor set];
      [thePath stroke];
   }

   //if linkedTo has passed the NS Test fill the arrow head else stroke it
   if([linkedTo passedNSTest]) {
      [arrowPath fill];
   } else {
      [arrowPath stroke];
   }

   if([linkType intValue] == SSTentativeLinkType) {
      [tentativeString drawAtPoint:tentativeStringPoint];
   }

   if([linkedFrom displayMode] == SSMatrixDisplayMode) {
      //only draw the diamonds in matrix mode
      [[NSColor blackColor] set];
      [[self needsDiamondArray] makeObjectsPerformSelector:@selector(draw)];
   }
}

- (void)update
{
   [thePath removeAllPoints];
   [arrowPath removeAllPoints];

   [self setPoints];
   [self setArrows];
   [self setPaths];
}

//***********************************
- (BOOL)isFullyWithinRect:(NSRect)rect
{
   NSRect bounds = [thePath bounds];
   NSPoint origin = bounds.origin;

   if(origin.x > NSMinX(rect)) { //it's ok on the left
      if(origin.x + NSWidth(bounds) < NSMaxX(rect)) { //it's ok on the right
         if(origin.y > NSMinY(rect)) { //it's ok at the bottom
            if(origin.y + NSHeight(bounds) < NSMaxY(rect)) { //it's ok at top
                                                                    //it's fullyWithinRect
               return YES;
            }
         }
      }
   }

   return NO;
}

- (BOOL)containsPoint:(NSPoint)point
{
   if([thePath containsPoint:point]) {
      return YES;
   } else {
      //the main path doesn't contain the point but the arraw may
      return [arrowPath containsPoint:point];
   }
}

- (BOOL)isSelected
{
   return isSelected;
}

- (void)setSelected
{
   isSelected = YES;
}

- (void)setUnselected
{
   isSelected = NO;
}


//***********************************
- (NSMutableArray *)needsDiamondArray
{
   return needsDiamondArray;
}

- (void)setNeedsDiamondArray:(NSMutableArray *)array
{
   [needsDiamondArray release];
   [array retain];
   needsDiamondArray = array;
}

- (void)addNeedsDiamond:(SSNeedsDiamond *)diamond
{
   [diamond setOwner:self];
   [needsDiamondArray addObject:diamond];   
}

- (void)removeNeedsDiamond:(SSNeedsDiamond *)diamond
{
   [needsDiamondArray removeObjectIdenticalTo:diamond];
}

- (void)removeAllNeedsDiamonds
{
   NSEnumerator *enumerator = [needsDiamondArray objectEnumerator];
   id anObject;

   while (anObject = [enumerator nextObject]) {
      [self removeNeedsDiamond:anObject];
   }
}

- (NSPoint)positionForNeedsDiamond:(SSNeedsDiamond *)diamond
{
   NSPoint pt1 = [thePath bounds].origin;
   NSPoint pt2 = NSMakePoint((NSMinX([thePath bounds]) + NSWidth([thePath bounds])), (NSMinY([thePath bounds]) + NSHeight([thePath bounds])));
   NSPoint diamondPoint;
   float ptxd = pt1.x - pt2.x;
   float ptyd = pt1.y - pt2.y;
   float pathLength = sqrt( ptxd*ptxd + ptyd*ptyd );
   float distanceAlongPath;
   //float segmentLength = (pathLength / ([needsDiamondArray count] + 2));
   //float distanceAlongPath = (segmentLength * ([needsDiamondArray indexOfObject:diamond] + 1));
   
   if((pathLength / ([needsDiamondArray count] * SSNeedsDiamondSize.width)) > 1) {
      distanceAlongPath = (SSNeedsDiamondSize.width * [needsDiamondArray indexOfObject:diamond]);
   } else {
      distanceAlongPath = ((SSNeedsDiamondSize.width * [needsDiamondArray indexOfObject:diamond]) *
                            (pathLength / ([needsDiamondArray count] * SSNeedsDiamondSize.width)));
   }
   
   double run = endPoint.x - startPoint.x;
   double rise = startPoint.y - endPoint.y;
   double slope = rise/run;
   double alpha = atan(slope);

   if(startPoint.x == endPoint.x) {//line is vertical
      if(startPoint.y < endPoint.y) {
         //it is heading down
         diamondPoint = NSMakePoint(startPoint.x
                                    , startPoint.y + distanceAlongPath);
      } else {
         //it is heading up
         diamondPoint = NSMakePoint(startPoint.x
                                    , startPoint.y - distanceAlongPath);
      }
   } else if(startPoint.y == endPoint.y) { //line is horizontal
      if(startPoint.x < endPoint.x) { //line is going right
         diamondPoint = NSMakePoint(startPoint.x + distanceAlongPath
                                    , startPoint.y);

      } else { //line is going right to left
         diamondPoint = NSMakePoint(startPoint.x - distanceAlongPath
                                    , startPoint.y);
      }
   } else if(startPoint.x < endPoint.x) { //line is going left to right
      if(startPoint.y < endPoint.y) {
         //going down right
         diamondPoint = NSMakePoint(startPoint.x + distanceAlongPath * cos(alpha)
                                    , startPoint.y - distanceAlongPath * sin(alpha));
      } else {
         //going up right
         diamondPoint = NSMakePoint(startPoint.x + distanceAlongPath * cos(alpha)
                                    , ((startPoint.y - distanceAlongPath * sin(alpha)) - SSNeedsDiamondSize.height));
      }
   } else { //line is going right to left
      if(startPoint.y < endPoint.y) {
         //going down left
         diamondPoint = NSMakePoint(startPoint.x - distanceAlongPath * cos(alpha)
                                    , startPoint.y + distanceAlongPath * sin(alpha));
      } else {
         //going up left
         diamondPoint = NSMakePoint(startPoint.x - distanceAlongPath * cos(alpha)
                                    , ((startPoint.y + distanceAlongPath * sin(alpha)) - SSNeedsDiamondSize.height));
      }
   }

   return diamondPoint;
}

//***********************************coding
- (void)encodeWithCoder:(NSCoder *)coder
{
   [coder encodeObject:linkedFrom forKey:@"linkedFrom"];
   [coder encodeObject:linkedTo forKey:@"linkedTo"];
   [coder encodeObject:linkType forKey:@"linkType"];
   [coder encodeObject:needsDiamondArray forKey:@"needsDiamondArray"];
}

- (id)initWithCoder:(NSCoder *)coder
{
   if(self = [super init]) {
      [self setLinkedFrom:[coder decodeObjectForKey:@"linkedFrom"]];
      [self setLinkedTo:[coder decodeObjectForKey:@"linkedTo"]];
      [self setLinkType:[coder decodeObjectForKey:@"linkType"]];

      if([coder containsValueForKey:@"needsDiamondArray"]) {
         [self setNeedsDiamondArray:[coder decodeObjectForKey:@"needsDiamondArray"]];
      } else {
         needsDiamondArray = [[NSMutableArray alloc] init];
      }
      

      thePath = [[NSBezierPath alloc] init];
      arrowPath = [[NSBezierPath alloc] init];
      tentativeString = [[NSAttributedString alloc] initWithString:@"?"];

      [self setPoints];
      [self setArrows];

      [thePath setLineWidth:SSConnectorLineWidth];

      [self setPaths];
   }
   return self;
}

//***********************************

- (void)dealloc
{
   [thePath release];
   [arrowPath release];
   [tentativeString release];
   [needsDiamondArray release];
   [super dealloc];
}

@end
